﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Runtime.ExceptionServices;
using System.Threading;

namespace NDK.Motion.Card
{

    //凌华运动控制卡
    [Serializable]
    public class Adlink : IMotionCard, IOCard
    {
        private static log4net.ILog traceLogger = log4net.LogManager.GetLogger("Adlink");

        #region fileds/properties
        private string _cardName;
        private int _cardID;
        private int _totalAxis;
        private int _inputCount;
        private int _outputCount;
        private string _adlinkCardType;
        private int _startAxisID;
        [NonSerialized]
        private bool _initialized;
        public string CardName
        {
            get
            {
                return _cardName;
            }

            set
            {
                _cardName = value;
            }
        }

        public int CardID
        {
            get
            {
                return _cardID;
            }

            set
            {
                _cardID = value;
            }
        }

        public int TotalAxis
        {
            get
            {
                return _totalAxis;
            }

            set
            {
                _totalAxis = value;
            }
        }

        public int InputCount
        {
            get
            {
                return _inputCount;
            }

            set
            {
                _inputCount = value;
            }
        }

        public int OutputCount
        {
            get
            {
                return _outputCount;
            }

            set
            {
                _outputCount = value;
            }
        }

        public string CardType
        {
            get
            {
                return _adlinkCardType;
            }

            set
            {
                _adlinkCardType = value;
            }
        }

        public int StartAxisID
        {
            get
            {
                return _startAxisID;
            }

            set
            {
                _startAxisID = value;
            }
        }

        public bool Initialized
        {
            get
            {
                return _initialized;
            }

            set
            {
                _initialized = value;
            }
        }

        public const int ON = 1;
        public const int OFF = 0;



        #endregion
        /// <summary>
        /// 初始化凌华板卡,mode默认为0（Card ID by system assigned）
        /// </summary>
        /// <param name="motionCards"></param>
        /// <param name="mode">
        /// * 00 0 0 0 0
        /// Bit0: Enable the On board dip switch (SW1) to decide the Card ID. [0:By system assigned, 1:By dip switch]
        /// Bit1: Parallel type axis indexing mode 0 : auto mode (default) 1 : fixed mode（普通卡，并行类型）
        /// Bit2: Serial type axis indexing mode 0: auto mode (default) 1: fixed mode （总线卡，串行类型）
        /// Bit4: Option of load  system & axes parameters method
        /// Bit5: (00B) 0: Do nothing, parameters keep current value. (01B) 1:Load from default. (02B)2:Load from flash.
        /// others: Reserved
        /// </param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool CardInit(ref List<ICard> motionCards, Int32 mode = 0)
        {
            //Card ID information in bit format. 
            //Example: If the value of BoardID_InBits is 0x11 which means that there are 2 cards in your system and those card‘s ID are 0 and 4. 
            Int32 boardID_InBits = 0;
            Int32 ret = 0;
            Int32 i = 0;
            Int32 card_name = 0;
            Int32 temp = 0;
            Int32 startAxisID = 0;
            Int32 totalAxisNum = 0;
            try
            {
                // Card(Board) initial
                Finalize();
                ret = APS168.APS_initial(ref boardID_InBits, mode);
                //if init success,load param file 
                if (ret == 0)
                {
                    for (i = 0; i < 16; i++)//搜索0~15bit
                    {
                        temp = (boardID_InBits >> i) & 1;
                        if (temp == 1)
                        {
                            APS168.APS_get_card_name(i, ref card_name);
                            if (card_name == (Int32)APSDefine.DEVICE_NAME_PCI_825458
                                || card_name == (Int32)APSDefine.DEVICE_NAME_AMP_20408C)
                            {
                                ret = APS168.APS_get_first_axisId(i, ref startAxisID, ref totalAxisNum);
                                Adlink card = new Adlink();
                                card.CardID = i;
                                card.CardType = ((ADLINK_CARD_TYPE)card_name).ToString();
                                card.TotalAxis = totalAxisNum;
                                card.InputCount = 24;
                                card.OutputCount = 24;
                                card.StartAxisID = startAxisID;
                                card.Initialized = true;
                                motionCards.Add(card);
                                //加载轴配置文件
                                card.LoadParamFile(Environment.CurrentDirectory + @"\Config\Param" + i.ToString() + ".xml", motionCards[i].CardID);
                            }
                        }
                    }
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink CardInit Exception:" + ex.StackTrace);
            }
            return true;
        }
        public bool CardInit(Int32 mode = 0)
        {
            //Card ID information in bit format. 
            //Example: If the value of BoardID_InBits is 0x11 which means that there are 2 cards in your system and those card‘s ID are 0 and 4. 
            Int32 boardID_InBits = 0;
            Int32 ret = 0;
            Int32 i = 0;
            Int32 card_name = 0;
            Int32 startAxisID = 0;
            Int32 totalAxisNum = 0;
            try
            {
                // Card(Board) initial
                Finalize();
                try
                {
                    ret = APS168.APS_initial(ref boardID_InBits, mode);
                }
                catch (Exception)
                {
                    return false;
                }
                //if init success,load param file 
                if (ret == 0)
                {
                    APS168.APS_get_card_name(this.CardID, ref card_name);
                    if (card_name == (Int32)APSDefine.DEVICE_NAME_PCI_825458
                        || card_name == (Int32)APSDefine.DEVICE_NAME_AMP_20408C)
                    {
                        ret = APS168.APS_get_first_axisId(i, ref startAxisID, ref totalAxisNum);
                        this.Initialized = true;
                        //加载轴配置文件
                        this.LoadParamFile(Environment.CurrentDirectory + @"\Config\Param" + i.ToString() + ".xml", this.CardID);
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink CardInit Exception:" + ex.StackTrace);
            }
            return false;
        }


        //7856
        //public bool CardInit(out List<ICard> cards, Int32 mode = 0)
        //{
        //    Int32 boardID_InBits = 0;
        //    //Int32 mode = 0;
        //    Int32 ret = 0;
        //    Int32 card_name = 0;
        //    int startAxisID = 0;
        //    int totalAxisNum = 0;
        //    Adlink card = new Adlink();
        //    cards = new List<ICard>();

        //    // Card(Board) initial
        //    ret += APS168.APS_close();
        //    ret += APS168.APS_initial(ref boardID_InBits, mode);

        //    //if init success,load param file 
        //    if (ret == 0)
        //    {
        //        ret += APS168.APS_stop_field_bus(0, 0);
        //        ret += APS168.APS_set_field_bus_param(0, 0, (Int32)APSDefine.PRF_HUB_NUMBER, 1);

        //        ret += APS168.APS_set_field_bus_param(0, 0, (Int32)APSDefine.PRF_TRANSFER_RATE, 3);
        //        ret += APS168.APS_start_field_bus(0, 1, 1500);//axis lianjie
        //        ret += APS168.APS_start_field_bus(0, 0, 0); //io lianjie

        //        ret = APS168.APS_get_first_axisId(0, ref startAxisID, ref totalAxisNum);

        //        card = new Adlink();
        //        card.CardID = 0;
        //        card.CardType = ((ADLINK_CARD_TYPE)card_name).ToString();
        //        card.TotalAxis = totalAxisNum;
        //        card.InputCount = 0;
        //        card.OutputCount = 0;
        //        card.StartAxisID = startAxisID;
        //        card.Initialized = true;
        //        cards.Add(card);

        //        if (ret == 0)
        //        {
        //            LoadParamFile(Environment.CurrentDirectory + @"\Config\Param0.xml", 0);
        //            Common.AppendUiLog.Log("Motion card " + 0 + " intial ok...", LogType.Info);
        //            Common.isCardInitialed = true;
        //        }
        //    }
        //    else
        //    {
        //        //m_Logger.Error("设置轴参数失败");
        //        Common.isCardInitialed = false;
        //        return false;
        //    }
        //    return true;
        //}
        /// <summary>
        /// 加载控制卡配置文件
        /// </summary>
        /// <param name="filePath">配置文件绝对路径</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool LoadParamFile(string filePath, int boardId)
        {
            int? ret = null;
            try
            {
                if (File.Exists(filePath))
                {
                    ret = APS168.APS_load_param_from_file(filePath);
                    if (ret != 0)
                    {
                        //m_Logger.Error("加载板卡配置文件失败");
                        return false;
                    }
                }
            }
            catch (Exception e)
            {
                traceLogger.Error("加载板卡配置文件失败" + e.Message);
                return false;
            }
            return true;
        }
        /// <summary>
        /// 获取指定位置，电机状态
        /// </summary>
        /// <param name="AxisId">轴ID</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetMotionStatus(short axisId, int motionStatusBit)
        {
            int? status = null;
            try
            {
                status = (APS168.APS_motion_status(axisId) >> motionStatusBit) & 1;

                if (status == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetMotionStatus Exception! " + ex.StackTrace);
            }
        }

        [HandleProcessCorruptedStateExceptions]
        public bool GetASTPStatus(short axisId)
        {
            try
            {
                return GetMotionStatus(axisId, (int)ADLINK_MOTION_STATUS_ENUM.MTS_ASTP);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetASTPStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetHMVStatus(short axisId)
        {
            try
            {
                return GetMotionStatus(axisId, (int)ADLINK_MOTION_STATUS_ENUM.MTS_HMV);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetHMVStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetNSTPStatus(short axisId)
        {
            try
            {
                return GetMotionStatus(axisId, (int)ADLINK_MOTION_STATUS_ENUM.MTS_NSTP);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetNSTPStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetCSTPStatus(short axisId)
        {
            try
            {
                return GetMotionStatus(axisId, (int)ADLINK_MOTION_STATUS_ENUM.MTS_CSTP);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetCSTPStatus Exception! " + ex.StackTrace);
            }
        }
        /// <summary>
        /// 获取电机IO状态
        /// </summary>
        /// <param name="AxisId">轴ID</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetMotionIoSatus(short axisId, int motionIoStatusBit)
        {
            int motionIoStatus = 0;
            try
            {
                motionIoStatus = APS168.APS_motion_io_status(axisId);
                motionIoStatus = (motionIoStatus >> motionIoStatusBit) & 1;
                if (motionIoStatus == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetMotionIoSatus Exception! " + ex.StackTrace);
            }
        }

        [HandleProcessCorruptedStateExceptions]
        public bool GetORGStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_ORG);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetORGStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetMELStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_MEL);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetMELStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetPELStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_PEL);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetPELStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetINPStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_INP);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetINPStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetEMGStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_EMG);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetEMGStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetALMStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_ALM);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetALMStatus Exception! " + ex.StackTrace);
            }
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetServoOnStatus(short axisId)
        {
            try
            {
                return GetMotionIoSatus(axisId, (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_SVON);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetServoOnStatus Exception! " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 单轴使能
        /// </summary>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public void AxisServoON(int Axis_ID, int Servo_On)
        {
            APS168.APS_set_servo_on(Axis_ID, Servo_On);
        }


        /// <summary>
        /// 获取电机实际位置（轴反馈）
        /// This function is used to get the position counter of one axis. The counter is in unit of pulse. 
        /// </summary>
        /// <param name="axisId">轴ID</param>
        /// <param name="position">实际位置</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetFeedbackPosition(short axisId, ref double feedbackPosition)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_position_f(axisId, ref feedbackPosition);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetFeedbackPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetCmdPosition(short axisId, ref double commandPosition)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_command_f(axisId, ref commandPosition);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetCmdPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetTargetPosition(short axisId, ref double targetPosition)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_target_position_f(axisId, ref targetPosition);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetTargetPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool GetErrorPosition(short axisId, ref double errorPosition)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_error_position_f(axisId, ref errorPosition);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetErrorPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        public bool GetFeedbackVelocity(short axisId, ref double feedbackVelocity)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_get_feedback_velocity_f(axisId, ref feedbackVelocity);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetErrorPosition Exception! " + ex.StackTrace);
            }
            return true;
        }
        /// <summary>
        /// 指定轴归零
        /// </summary>
        /// <param name="axisId">轴ID</param>
        /// <param name="homeMode">回零模式</param>
        /// <param name="homeDir">搜索方向</param>
        /// <param name="homeCure">曲线</param>
        /// <param name="homeAcc">回零加速度</param>
        /// <param name="homeVm">回零最大速度</param>
        /// <param name="homeVo">回零初速度</param>
        /// <param name="homeShiftDistance">回零偏移</param>
        /// <param name="stopDec">停止减速度</param>
        /// <param name="isEnableSoftLimit">是否使能软限位</param>
        /// <param name="spelPos">正软限位位置</param>
        /// <param name="smelPos">负软限位位置</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool HomeMove(short axisId, PRA_HOME_ENUM homeMode, DIR_ENUM homeDir, PRA_SF_ENUM homeCure, double homeAcc, double homeVm, double homeVo, double homeShiftDistance, double stopDec, SWITCH_ENUM isEnableSoftLimit, double spelPos, double smelPos)
        {
            int? ret = 0;

            try
            {
                // 1. Select home mode and config home parameters 
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_HOME_MODE, (int)homeMode); // Set home mode
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_HOME_DIR, (int)homeDir); // Set home direction
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_HOME_CURVE, (int)homeCure); // Set acceleration paten （0 --> 1：T --> S）
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_HOME_ACC, homeAcc); // Set homing acceleration rate
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_VM, homeVm); // Set homing maximum velocity.
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_VO, homeVm); // Set homing VO speed
                ret += APS168.APS_set_axis_param(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_EZA, (int)0); // Set EZ signal alignment (yes or no)
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_SHIFT, homeShiftDistance); // Set home position shfit distance. 
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_HOME_POS, 0); // Set final home position.

                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SD_DEC, stopDec); // Set up rate for deceleration stop.
                ret += APS168.APS_set_axis_param(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SPEL_EN, (int)isEnableSoftLimit); // Soft PEL switch.
                ret += APS168.APS_set_axis_param(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SMEL_EN, (int)isEnableSoftLimit); // Soft MEL switch.
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SPEL_POS, spelPos); // Soft-PEL position.
                ret += APS168.APS_set_axis_param_f(Convert.ToInt16(axisId), (Int32)APSDefine.PRA_SMEL_POS, smelPos); // Soft-MEL position.

                ret += APS168.APS_set_servo_on(Convert.ToInt16(axisId), 1);
                ret += APS168.APS_home_move(Convert.ToInt16(axisId));
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="axisId"></param>
        /// <param name="dir"></param>
        /// <param name="acc"></param>
        /// <param name="dec"></param>
        /// <param name="vm"></param>
        /// <param name="SF"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool MoveVel(short axisId, DIR_ENUM dir, double acc, double dec, double vm, double SF = 0.5)
        {
            int ret = 0;
            ASYNCALL p = new ASYNCALL();
            try
            {
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_STP_DEC, dec);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_CURVE, 0.5); //Set acceleration rate
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_ACC, acc); //Set acceleration rate
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_DEC, dec); //Set deceleration rate

                ret += APS168.APS_vel(axisId, (int)dir, vm, ref p);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("MoveVel Exception! " + ex.StackTrace);
            }
            return true;

        }
        /// <summary>
        /// JOG到指定位置
        /// </summary>
        /// <param name="AxisId">轴ID</param>
        /// <param name="ApsOption">轴方向</param>
        /// <param name="vm">运行速度</param>
        /// <param name="acc">加减速</param>
        /// <param name="position">位置</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool PTPMove(short axisId, PRA_OPTION_ENUM ApsOption, double vm, double acc, double dec, double position)
        {
            int ret = 0;
            ASYNCALL Wait = new ASYNCALL();
          
            try
            {
                // Config speed profile parameters.
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_SF, 0.5);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_ACC, acc);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_DEC, dec);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_VM, vm);
                //APS_ptp:This function is used to execute a single move by axis. 
                //No any suffix represents that no any motion profile is necessary to perform a single move. 
                //Other motion profiles are set in axis parameters. 
                ret += APS168.APS_ptp(axisId, Convert.ToInt16(ApsOption), position, ref Wait);

                //APS_ptp
                //This function is used to execute a single move by axis.
                //The _v suffix represents that only one motion profile, that is Vm, 
                //is necessary to perform a single move.Other motion profiles are set in axis parameters.
                //ret += APS168.APS_ptp_v(axisId, Convert.ToInt16(ApsOption), position,vm, ref Wait);

                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Axis[" + axisId + "] ,Adlink PTPMove Exception!" + ex.StackTrace);
            }
            return true;
        }
        [HandleProcessCorruptedStateExceptions]
        public bool Finalize()
        {
            try
            {
                if (APS168.APS_close() == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }

        }

        [HandleProcessCorruptedStateExceptions]
        public void PointTableMove(Int32 _cardId, Int32 axis0, Int32 axis1, Double[] x, Double[] y, double vm, double acc)
        {
            PTSTS ptStatus = new PTSTS();
            PTLINE Line = new PTLINE();
            PTDWL dwell = new PTDWL();
            dwell.DwTime = 200;


            int cardid = _cardId;
            Int32 ptbId = 0, dimension = 2;
            int[] axisIdArray = new int[] { axis0, axis1 };

            int ret = APS168.APS_pt_disable(cardid, ptbId);
            ret = APS168.APS_pt_enable(cardid, ptbId, dimension, axisIdArray);

            ret = APS168.APS_pt_set_absolute(cardid, ptbId);
            ret = APS168.APS_pt_set_trans_buffered(cardid, ptbId);
            ret = APS168.APS_pt_set_acc(cardid, ptbId, acc);
            ret = APS168.APS_pt_set_dec(cardid, ptbId, acc);
            ret = APS168.APS_pt_set_vm(cardid, ptbId, vm);
            ret = APS168.APS_pt_set_ve(cardid, ptbId, vm);
            ret = APS168.APS_pt_set_s(cardid, ptbId, 0.5);
            for (int i = 0; i < x.Length; i++)
            {
                while (true)
                {

                    Line.Dim = dimension;

                    Line.Pos = new Double[] { Convert.ToDouble(x[i]), Convert.ToDouble(y[i]), 0, 0, 0, 0 };
                    ret = APS168.APS_pt_line(cardid, ptbId, ref Line, ref ptStatus);

                    break;

                }
            }
            APS168.APS_pt_start(cardid, 0);
            bool ptbFlag = true;
            while (ptbFlag)
            {
                int motionStatus = APS168.APS_motion_status(axisIdArray[0]);
                ret = APS168.APS_get_pt_status(cardid, ptbId, ref ptStatus);
                uint _bufRunningCnt = ptStatus.RunningCnt;
                if (_bufRunningCnt >= x.Length - 1)
                {
                    ptbFlag = false;
                }
                Thread.Sleep(100);
            }
            int cnt = 0;
            APS168.APS_get_trigger_count(cardid, 0, ref cnt);
        }

        [HandleProcessCorruptedStateExceptions]
        public void TwoDtrigger(Int32 _cardId, Int32 TGR_SRC, Int32 axis0, Int32 axis1, Double[] x, Double[] y, Int32 windows, Int32 width)
        {
            Int32 size;
            size = x.Length;
            //设置触发点
            const int TGR_MCMP0_SRC = 48;
            const int TGR_MCMP1_SRC = 49;
            APS168.APS_set_trigger_param(_cardId, TGR_MCMP0_SRC, axis0);
            APS168.APS_set_trigger_param(_cardId, TGR_MCMP1_SRC, axis1);
            switch (TGR_SRC)
            {
                case 0:
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG0_SRC, Convert.ToInt32("1000001", 2));
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG0_PWD, width);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG0_LOGIC, 1);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG_EN, Convert.ToInt32("0001", 2));
                    break;
                case 1:
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG1_SRC, Convert.ToInt32("1000001", 2));
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG1_PWD, width);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG1_LOGIC, 0);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG_EN, Convert.ToInt32("0010", 2));
                    break;
                case 2:
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG2_SRC, Convert.ToInt32("1000001", 2));
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG2_PWD, width);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG2_LOGIC, 0);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG_EN, Convert.ToInt32("0100", 2));
                    break;
                case 3:
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG3_SRC, Convert.ToInt32("1000001", 2));
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG3_PWD, width);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG3_LOGIC, 0);
                    APS168.APS_set_trigger_param(_cardId, (Int32)APSDefine.TGR_TRG_EN, Convert.ToInt32("1000", 2));
                    break;
            }

            MCMP_POINT[] trPos = new MCMP_POINT[size];
            for (int i = 0; i < size; i++)
            {
                //trPos[i] = new MCMP_POINT(x[i], y[i], 0, 0, 0xf);
            }

            APS168.APS_set_multi_trigger_table(_cardId, 2, trPos, size, windows);
        }


        /// <summary>
        /// 获取电机实际位置
        /// </summary>
        /// <param name="axisId">轴ID</param>
        /// <param name="position">实际位置</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetPosition(short axisId, ref double position)
        {
            int? ret = null;
            // axisMagnification = new MAGNIFICATION[2000];
            double PositionFun = 0;
            try
            {
                ret = APS168.APS_get_position_f(Convert.ToInt16(axisId, CultureInfo.InvariantCulture), ref PositionFun);

                if (ret != 0)
                {
                    //m_Logger.Error("Fail to get axis's current position");
                    return false;
                }
            }
            catch (Exception e)
            {
                //m_Logger.Error("Get axis's  current position exception!" + e.Message);
                return false;
            }
            return true;
        }



        /// <summary>
        /// 获得某个输入端口的值(20408C)
        /// </summary>
        /// <param name="cardId"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetDI(int card, int port = 0)
        {
            bool ret = false;
            int inputValue = 0;
            try
            {

                if (APS168.APS_read_d_input(_cardID, 0, ref inputValue) == 0)//读取成功
                {
                    int v = (inputValue >> port) & 1;
                    if (v == 0)
                    {
                        ret = false;
                    }
                    else
                    {
                        ret = true;
                    }
                }
                else//读取失败
                {
                    throw new Exception("APS_read_d_input Err!");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("APS_read_d_input Exception!" + ex.StackTrace);
            }
            return ret;
        }
        /// <summary>
        /// 获得某个输出端口的值
        /// </summary>
        /// <param name="boardID"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetDO(int card, int port = 0)
        {
            int outputValue = 0;
            bool ret = false;
            try
            {
                if (APS168.APS_read_d_output(_cardID, 0, ref outputValue) == 0)//读取成功
                {
                    if (((outputValue >> port) & 1) == 0)
                    {
                        ret = false;
                    }
                    else
                    {
                        ret = true;
                    }
                }
                else//读取失败
                {
                    throw new Exception("APS_read_d_output Err!");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("APS_read_d_output Exception!" + ex.StackTrace);
            }
            return ret;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="boardID"></param>
        /// <param name="port"></param>
        /// <param name="ONOrOFF"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool SetDO(int card, int port, int ONOrOFF = 0)
        {
            try
            {

                int ret = APS168.APS_write_d_channel_output(_cardID, 0, port, ONOrOFF);
                if (ret != 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("APS_write_d_channel_output Err!" + ex.StackTrace);
            }
        }
        /// <summary>
        /// 急停
        /// It can stop single axis homing, positioning and speed moving.
        /// </summary>
        /// <param name="axisId">轴ID</param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool StopEmg(short axisId)
        {
            int? ret = 0;
            try
            {
                ret = APS168.APS_emg_stop(axisId);
                //double curPos = 0.0;
                //Thread.Sleep(100);
                //ret += APS168.APS_get_position_f(axisId, ref curPos);
                //ret += APS168.APS_set_command_f(axisId, curPos);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("StopEmg Exception(axisId:" + axisId + ")! " + ex.StackTrace);
            }
            return true;
        }
        /// <summary>
        /// 减速停止
        ///  It can stop single axis homing, positioning and speed moving. 
        /// </summary>
        /// <param name="axisId">轴号</param>
        /// <param name="acc"></param>
        /// <returns>true:成功；false：失败；异常抛出</returns>
        [HandleProcessCorruptedStateExceptions]
        public bool StopMove(short axisId, double dec)
        {
            int? ret = 0;

            try
            {
                //ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_STP_DEC, dec);
                ret += APS168.APS_stop_move((int)axisId);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("StopMove Exception(axisId:" + axisId + ")! " + ex.StackTrace);
            }
            return true;
        }
        /// <summary>
        /// 多轴直线插补运动
        /// </summary>
        /// <param name="axisIdArray"></param>
        /// <param name="axisPosArray"></param>
        /// <param name="APSOPTION"></param>
        /// <param name="vm"></param>
        /// <param name="acc"></param>
        /// <param name="dec"></param>
        /// <param name="SF"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool InterPolationLine(int[] axisIdArray, double[] axisPosArray, PRA_OPTION_ENUM apsOption, double vm, double acc = 0.1, double dec = 0.1, PRA_SF_ENUM SF = PRA_SF_ENUM.S_CURVE)
        {
            int? ret = 0;
            double[] positionArray = new double[10];
            double[] Vm = new double[10];
            double[] Acc = new double[10];
            double[] Dec = new double[10];
            double transPara = 0.0;
            ASYNCALL wait = new ASYNCALL();


            try
            {
                if (axisIdArray.Length == axisPosArray.Length)
                {
                    for (int axisNumIndex = 0; axisNumIndex < axisPosArray.Length; axisNumIndex++)
                    {
                        Vm[axisNumIndex] = vm ;
                        Acc[axisNumIndex] =  acc;
                        Dec[axisNumIndex] =  dec;
                        positionArray[axisNumIndex] = axisPosArray[axisNumIndex];

                        ret += APS168.APS_set_axis_param(axisIdArray[axisNumIndex], (Int32)APSDefine.PRA_SF, (Int32)SF);
                        ret += APS168.APS_set_axis_param_f(axisIdArray[axisNumIndex], (Int32)APSDefine.PRA_ACC, Acc[axisNumIndex]);
                        ret += APS168.APS_set_axis_param_f(axisIdArray[axisNumIndex], (Int32)APSDefine.PRA_DEC, Dec[axisNumIndex]);
                        ret += APS168.APS_set_axis_param_f(axisIdArray[axisNumIndex], (Int32)APSDefine.PRA_VM, Vm[axisNumIndex]);
                    }
                    //ret += APS168.APS_line(axisIdArray.Length, axisIdArray, (int)apsOption, positionArray, ref transPara, ref wait);
                    P2PMoveWait(axisIdArray, positionArray, apsOption, Vm, Acc, Dec);
                    if (ret != 0)
                    {
                        //m_Logger.Error("轴" + axisIdArray[axisNumIndex] + "InterPolationLine失败！");
                        //return false;
                    }
                }
            }
            catch (Exception ex)
            {
                //m_Logger.Error("多轴直线插补运动失败！" + ex.StackTrace);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 获取急停状态
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetEmgStatus(short axisId)
        {
            try
            {
                if (((APS168.APS_motion_io_status(Convert.ToInt16(axisId)) >> (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_EMG) & 1) == 1)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetEmgStatus Exception! " + ex.StackTrace);
            }
        }
        /// <summary>
        /// 获取轴的报警状态（Motion IO status 的第0位）
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetAxisAlarmStatus(short axisId)
        {
            try
            {
                if (((APS168.APS_motion_io_status(Convert.ToInt16(axisId)) >> (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_ALM) & 1) == 1)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetAxisAlarmStatus Exception! " + ex.StackTrace);
            }
        }
        /// <summary>
        /// 获取轴的负限位状态（Motion IO status 的第2位）
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetAxisMelStatus(short axisId)
        {
            try
            {
                if (((APS168.APS_motion_io_status(Convert.ToInt16(axisId)) >> (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_MEL) & 1) == 1)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetAxisMelStatus Exception! " + ex.StackTrace);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool GetAxisPelStatus(short axisId)
        {
            try
            {
                if (((APS168.APS_motion_io_status(Convert.ToInt16(axisId)) >> (int)ADLINK_MOTION_IO_STATUS_ENUM.MIO_PEL) & 1) == 1)
                    return true;
                else
                    return false;
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink GetAxisPelStatus Exception! " + ex.StackTrace);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="axisId"></param>
        /// <param name="apsOption"></param>
        /// <param name="jogVm"></param>
        /// <param name="jogAcc"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool JogMoveStart(short axisId, DIR_ENUM apsOption, double jogVm, double jogAcc)
        {
            int? ret = null;
            try
            {

                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_JG_MODE, 0);
                ret += APS168.APS_set_axis_param(axisId, (Int32)APSDefine.PRA_JG_DIR, (int)apsOption);

                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_JG_CURVE, 0.0);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_JG_ACC, jogAcc);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_JG_DEC, jogAcc);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_JG_VM, jogVm);
                // Create a rising edge.
                ret += APS168.APS_jog_start(axisId, OFF);
                ret += APS168.APS_jog_start(axisId, ON);
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool JogMoveStop(short axisId)
        {
            int? ret = null;
            try
            {
                ret += APS168.APS_jog_start((int)axisId, ON);  //Jog On
                ret += APS168.APS_jog_start((int)axisId, OFF);  //Jog Off
                if (ret != 0)
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 失能所有轴
        /// </summary>
        [HandleProcessCorruptedStateExceptions]
        public bool ServoOff(int axisId)
        {
            try
            {
                return (APS168.APS_set_servo_on(axisId, OFF) == 0);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink ServoOff Exception !" + ex.StackTrace);
            }
        }
        /// <summary>
        /// 使能轴
        /// </summary>
        [HandleProcessCorruptedStateExceptions]
        public bool ServoON(int axisId)
        {
            try
            {
                return (APS168.APS_set_servo_on(axisId, ON) == 0);
            }
            catch (Exception ex)
            {
                throw new Exception("Adlink ServoON Exception !" + ex.StackTrace);
            }
        }
        /// <summary>
        /// 检查轴是否在运动
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool IsMoving(int axisId)
        {
            return (!CheckMoveDone((short)axisId));
        }

        /// <summary>
        /// 检测运动是否完成
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool CheckMoveDone(short axisId)
        {
            int stopCode = 0;
            // Get motion done bit,normal stop
            int status = APS168.APS_motion_status(axisId);
            int isMotionDone = (status >> (int)APSDefine.NSTP) & 1; // // Normal stop(Motion done).            
            if (1 == isMotionDone)//正常停止后，二次检查停止原因
            {
                //abnormal stop
                status = ((APS168.APS_motion_status(axisId) >> (int)APSDefine.MTS_ASTP)) & 1;
                if (status == 1)//abnormal stop
                {
                    //用APS_get_stop_code获取停止原因：
                    //Symbol              Code      Description             
                    //STOP_NORMAL          0        Stop normally             
                    //STOP_EMG             1        Stop when EMG is turn ON             
                    //STOP_ALM             2        Stop when ALM is turn ON             
                    //STOP_SVNO            3        Stop when servo is turn - OFF             
                    //STOP_PEL             4        Stop by PEL signal turn ON            
                    //STOP_MEL             5        Stop by MEL signal turn ON             
                    //STOP_SPEL            6        Stop by soft - limit condition – positive end limit             
                    //STOP_SMEL            7        Stop by soft - limit condition – minus end limit             
                    //STOP_USER_EMG        8        EMG stop by user              
                    //STOP_USER            9        Stop by user             
                    //STOP_GAN_L1          10       Stop by E - Gear gantry protect level 1 condition is met.            
                    //STOP_GAN_L2          11       Stop by E - Gear gantry protect level 2 condition is met            
                    //STOP_GEAR_SLAVE      12       Stop because gear slave axis             
                    //STOP_ERROR_LEVEL     13       Error position check level            
                    //STOP_DI              14       DI            
                    //APS168.APS_get_stop_code(axisId, ref stopCode);
                }

                if (stopCode != 0)
                {
                    throw new Exception("Adlink CheckMoveDone " + Enum.GetName(typeof(ADLINK_STOP_CODE_ENUM), stopCode) + " !");
                }
                else
                {
                    return true;
                }
            }

            return false;//in motion
        }

        [HandleProcessCorruptedStateExceptions]
        public bool SetPos(int axisId, double pos)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_set_position_f(axisId, pos);
                if (ret != 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception)
            {
                throw new Exception("APS_set_position_f Exception!");
            }
        }

        /// <summary>
        /// 报警清除
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool ClearAlarm(short axisId)
        {
            //204/8C用前4/8个IO来接到驱动器上.做报警清除使用(根据接线编写)
            ServoON(axisId);
            return true;
        }

        //点到点移动(模式可供选择：绝对移动、相对移动）
        [HandleProcessCorruptedStateExceptions]
        public void P2PMoveWait(int[] axisIdArray, double[] axisPosArray, PRA_OPTION_ENUM apsOption, double[] vm, double[] acc, double[] dec)
        {
            int ret = 0;
            for (int i = 0; i < axisIdArray.Length; i++)
            {
                int axisId = axisIdArray[i];
                ASYNCALL p = new ASYNCALL();

                ret = APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_VM, vm[i]);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_ACC, acc[i]);
                ret += APS168.APS_set_axis_param_f(axisId, (Int32)APSDefine.PRA_DEC, dec[i]);
                ret += APS168.APS_ptp(axisId, (int)apsOption, (int)(axisPosArray[i]), ref p);
            }



        }
        public bool InitialPointTableTrigger(uint mode, int triggerOutNumber, int width, int encoderNo, int preCompareMask, int dir)
        {
            try
            {
                //重置触发计数
                APS168.APS_reset_trigger_count(CardID, 0);
                //关闭触发
                APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG_EN, 0);
                //打开指定通道的触发 TRG 0 ~ 3 enable by bit
                // Bit x: (0: disable, 1: enable) Bit 0:TRG0 enable Bit 1:TRG1 enable Bit 2:TRG2 enable Bit 3:TRG3 enable
                APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG_EN, 1 << preCompareMask);//0,1,2,3
                if (preCompareMask == 0)
                {
                    //将 比较器TGR_TCMP0_SRC 绑定到编码器 encoderNo 
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TCMP0_SRC, encoderNo);
                    //Bi-direction(No direction)
                    //0: Negative direction
                    //1: Positive direction
                    //2: Bi - direction(No direction)
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TCMP0_DIR, dir);
                    //将 比较器 TGR_TRG0_SRC 绑定到 触发输出通道triggerOutNumber
                    //Trigger output 0 (TRG0) source : Bit( 1:On, 0:Off)    Bit 0: Manual  Bit 1:Reserved Bit  2:TCMP0  Bit 3:TCMP1  Bit 4:LCMP0  Bit 5:LCMP1  Bit 6:MCMP
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG0_SRC, 1 << triggerOutNumber);
                    //TRG0 pulse width 触发脉宽
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG0_PWD, width); //  pulse width=  value * 0.02 us 5w=1ms
                                                                                                //TRG 1 logic  0: Not inverse  1:Inverse
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG0_LOGIC, 0);
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG0_TGL, 0);
                }
                if (preCompareMask == 1)
                {
                    //Source Encoder 轴绑定
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TCMP1_SRC, encoderNo);
                    //Bi-direction(No direction)
                    //0: Negative direction
                    //1: Positive direction
                    //2: Bi - direction(No direction)
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TCMP1_DIR, dir);
                    //Trigger output  (TRG0) source Bit( 1:On, 0:Off)    Bit 0: Manual  Bit 1:Reserved Bit  2:TCMP0  Bit 3:TCMP1  Bit 4:LCMP0  Bit 5:LCMP1  Bit 6:MCMP
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG1_SRC, 1 << triggerOutNumber);
                    //TRG1 pulse width 触发脉宽
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG1_PWD, width); //  pulse width=  value * 0.02 us 5w=1ms
                                                                                                //TRG 1 logic  0: Not inverse  1:Inverse
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG1_LOGIC, 0);
                    APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG1_TGL, 0);
                }

            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="preCompareMask">触发使能通道0-3</param>
        /// <param name="axisId"></param>
        /// <param name="pointTablePositions"></param>
        /// <returns></returns>
        public bool AddPointTableTriggerPositions(int preCompareMask, int axisId, List<double> pointTablePositions)
        {
            //重置触发计数
            int ret = 0;
            try
            {
                ret = APS168.APS_reset_trigger_count(CardID, 0);
                ret += APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG_EN, 0);
                //TRG 0 ~ 3 enable by bit 
                ret += APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG_EN, 1 << preCompareMask);//

                List<int> list = new List<int>();
                for (int i = 0; i < pointTablePositions.Count; i++)
                {
                    int temp = (int)(pointTablePositions[i]);
                    list.Add(temp);
                }

                if (list.Count > 0)
                {
                    ret += APS168.APS_set_trigger_table(CardID, 0, list.ToArray(), list.Count);
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            if (ret != 0)
            {
                return false;
            }
            return true;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="TriggerOutNum">0,1</param>
        public void TriggerOut_SetManualOutput(int TriggerOutNum)
        {
            int ret = APS168.APS_set_trigger_param(CardID, (int)APSDefine.TGR_TRG_EN, 0x3);
            //TRG1 pulse width 触发脉宽
            APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG0_PWD, 250000); //  pulse width=  value * 0.02 us 5w=1ms
                                                                                         //TRG 1 logic  0: Not inverse  1:Inverse
            APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG0_LOGIC, 0);
            APS168.APS_set_trigger_param(CardID, (short)APSDefine.TGR_TRG0_TGL, 0);
            //Trigger output TRG0 ~ TRG3 source
            //Bit 0: Manual 
            //Bit 1: Reserved
            //Bit 2: FCMP0 
            //Bit 3: FCMP1 
            //Bit 4: LCMP0 
            //Bit 5: LCMP1
            ret = APS168.APS_set_trigger_param(CardID, (Int32)APSDefine.TGR_TRG0_SRC, 0x1);
            ret = APS168.APS_set_trigger_param(CardID, (Int32)APSDefine.TGR_TRG1_SRC, 0x1);
            ret = APS168.APS_set_trigger_param(CardID, (Int32)APSDefine.TGR_TRG2_SRC, 0x1);
            ret = APS168.APS_set_trigger_param(CardID, (Int32)APSDefine.TGR_TRG3_SRC, 0x1);

            int CH;
            //Start manual trigger
            ret = APS168.APS_set_trigger_manual(CardID, TriggerOutNum);
        }

        /// <summary>
        /// 初始化连续插补运动
        /// </summary>
        /// <param name="ptbId">Point table id 0</param>
        /// <param name="dimension">插补维度</param>
        /// <param name="idList">需要插补的轴号</param>
        public bool InitContinueInterpolation(short ptbId, short dimension, List<int> idList)
        {

            Int32[] Axis_ID_Array = idList.ToArray();
            int ret;
            //Enable point table
            ret = APS168.APS_pt_disable(CardID, ptbId);
            ret += APS168.APS_pt_enable(CardID, ptbId, dimension, Axis_ID_Array);

            //Configuration
            ret += APS168.APS_pt_set_absolute(CardID, ptbId); //Set to absolute mode
            ret += APS168.APS_pt_set_trans_buffered(CardID, ptbId); //Set to buffer mode
            if (ret != 0)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 连续运动压入一个直边点
        /// </summary>
        /// <param name="ptbId">压入到指定点表ID</param>
        /// <param name="startVel">起始速度</param>
        /// <param name="vel">运行速度</param>
        /// <param name="acc">加减速时间</param>
        /// <param name="axisIds">参与插补的轴号</param>
        /// <param name="posList">参与插补的轴对应的点位</param>
        /// <returns></returns>
        public bool AddContinueInterpolationPos_Line(short ptbId, double startVel, double vel, double acc, List<int> axisIds, List<double> posList)
        {
            PTSTS Status = new PTSTS();
            PTLINE Line = new PTLINE();
            int dimension = axisIds.Count;

            //压入pos
            List<double> tepmPosList = new List<double>();
            for (int j = 0; j < dimension; j++)//循环维度
            {
                double temp = (posList[j]);
                tepmPosList.Add(temp);
            }
            double[] posArray = tepmPosList.ToArray();
          

            //Get status
            int ret = APS168.APS_get_pt_status(CardID, ptbId, ref Status);
            if ((Status.BitSts & 0x02) == 0) //Buffer is not Full
            {
                //Set 2nd move profile
                ret += APS168.APS_pt_set_acc(CardID, ptbId, acc); //Set acc
                ret += APS168.APS_pt_set_dec(CardID, ptbId, acc); //Set dec

                ret += APS168.APS_pt_set_vm(CardID, ptbId, vel); //Set vm to 12000
                ret += APS168.APS_pt_set_ve(CardID, ptbId, startVel); //Set ve to 6000

                //Set pt line data
                Line.Dim = dimension;

                double[] poss = new Double[] { 0, 0, 0, 0, 0, 0 };
                for (int i = 0; i < dimension; i++)
                {
                    poss[i] = posArray[i];
                }
                Line.Pos = poss;// new Double[] { 0, 0, 0, 0, 0, 0 };

                //Push 2nd point to buffer
                ret += APS168.APS_pt_line(CardID, ptbId, ref Line, ref Status);
            }
            else//点表满了，压点失败
            {
                return false;
            }
            if (ret != 0)
            {
                return false;
            }
            return true;
        }
      
        /// <summary>
        /// 连续运动压入DO
        /// </summary>
        /// <param name="ptbId"></param>
        /// <param name="channel"></param>
        /// <param name="ONOrOFF"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool PointTableAddDO(int ptbId, int channel, int ONOrOFF)
        {
            try
            {
                int ret;

                ret = APS168.APS_pt_ext_set_do_ch(CardID, ptbId, channel, ONOrOFF);

                if (ret == 0)
                {
                    return true;
                }

                return false;
            }
            catch (Exception ex)
            {
                throw new Exception("PointTableAddDO Exception! " + ex.StackTrace);
            }

        }

        public bool StartContinueInterpolation(short ptbId)
        {

            int ret = APS168.APS_pt_start(CardID, ptbId);//使对应点表开始连续插补运动

            if (ret != 0)
            {
                return false;
            }
            return false;
        }
        public bool StopContinueInterpolation(short ptbId)
        {
            int ret = APS168.APS_pt_stop(CardID, ptbId);//使对应点表定制连续插补运动

            if (ret != 0)
            {
                return false;
            }
            return false;
        }

        public bool StartGear(short axisId, GEAR_MODE mode)
        {
            int ret = 0;
            try
            {
                ret = APS168.APS_start_gear(axisId, (int)mode);
                if (ret == 1)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("StartGear Exception! " + ex.StackTrace);
            }
        }


        /// <summary>
        /// 检测是否在回零
        /// </summary>
        /// <param name="axisId"></param>
        /// <returns></returns>
        [HandleProcessCorruptedStateExceptions]
        public bool IsHoming(int axisID)
        {
            int status = APS168.APS_motion_status(axisID);

            int isMotionDone = (status >> (int)APSDefine.MTS_HMV) & 1; //正在回零
            if (isMotionDone == 1)
            {
                return true;
            }
            else
            {
                return false;

            }
        }

        public void UpdateSlaveResource(ref ICard card, int mode = 0)
        {
            throw new NotImplementedException();
        }
    }


    public enum ADLINK_CARD_TYPE
    {
        //ADLINK_MOTION_CARD,
        PCI_8392 = 0,
        PCI_825x,
        PCI_8154,
        PCI_785X,
        PCI_8158,
        PCI_7856,
        ISA_DPAC1000,
        ISA_DPAC3000,
        PCI_8144,
        PCI_8258,
        PCI_8102,
        PCI_V8258,
        PCI_V8254,
        PCI_8158A,
        PCI_20408C,
    }

    public enum ADLINK_MOTION_IO_STATUS_ENUM
    {
        MIO_ALM = 0,   // Servo alarm.
        MIO_PEL = 1,   // Positive end limit.
        MIO_MEL = 2,   // Negative end limit.
        MIO_ORG = 3,   // ORG =Home
        MIO_EMG = 4,   // Emergency stop
        MIO_EZ = 5,    // EZ.
        MIO_INP = 6,   // In position.
        MIO_SVON = 7,  // Servo on signal.
        MIO_RDY = 8,   // Ready.
        MIO_WARN = 9,  // Warning.
        MIO_ZSP = 10,  // Zero speed.
        MIO_SPEL = 11, // Soft positive end limit.
        MIO_SMEL = 12, // Soft negative end limit.
        MIO_TLC = 13,  // Torque is limited by torque limit value.
        MIO_ABSL = 14, // Absolute position lost.
        MIO_STA = 15,  // External start signal.
        MIO_PSD = 16,  // Positive slow down signal
        MIO_MSD = 17,  // Negative slow down signal

    }
    public enum ADLINK_MOTION_STATUS_ENUM
    {
        //Motion status bit number define.
        MTS_CSTP = 0,  //Command stop signal.
        MTS_VM = 1,   // At maximum velocity.
        MTS_ACC = 2,  //In acceleration.
        MTS_DEC = 3,  // In deceleration.
        MTS_DIR = 4,  // LastMoving direction.
        MTS_NSTP = 5, // Normal stop(Motion done.
        MTS_HMV = 6,  //In home operation.
        MTS_SMV = 7,  //Single axis move relative, absolute, velocity move.
        MTS_LIP = 8,  //Linear interpolation.
        MTS_CIP = 9,  // Circular interpolation.
        MTS_VS = 10,  // At start velocity.
        MTS_PMV = 11,  // Point table move.
        MTS_PDW = 12,  // Point table dwell move.
        MTS_PPS = 13,  // Point table pause state.
        MTS_SLV = 14,  //Slave axis move.
        MTS_JOG = 15,  //Jog move.
        MTS_ASTP = 16, // Abnormal stop.
        MTS_SVONS = 17, // Servo off stopped.
        MTS_EMGS = 18,  // EMG / SEMG stopped.
        MTS_ALMS = 19,  // Alarm stop.
        MTS_WANS = 20,  //Warning stopped.
        MTS_PELS = 21,  //PEL stopped.
        MTS_MELS = 22,  //MEL stopped.
        MTS_ECES = 23,  //Error counter check level reaches and stopped.
        MTS_SPELS = 24,  // Soft PEL stopped.
        MTS_SMELS = 25,  //Soft MEL stopped.
        MTS_STPOA = 26,  // Stop by others axes.
        MTS_GDCES = 27,  //Gantry deviation error level reaches and stopped.
        MTS_GTM = 28,    //Gantry mode turn on.
        MTS_PAPB = 29  // Pulsar mode turn on.
    }

    public enum ADLINK_STOP_CODE_ENUM
    {
        STOP_NORMAL = 0,
        STOP_EMG,
        STOP_ALM,
        STOP_SVNO,
        STOP_PEL,
        STOP_MEL,
        STOP_SPEL,
        STOP_SMEL,
        STOP_USER_EMG,
        STOP_USER,
        STOP_GAN_L1,
        STOP_GAN_L2,
        STOP_GEAR_SLAVE,
        STOP_ERROR_LEVEL,
        STOP_DI
    }
}